POV-Ray : Newsgroups : povray.programming : POV-Ray on non-IEEE floating-point compatible platforms : Re: POV-Ray on non-IEEE floating-point compatible platforms Server Time
28 Jul 2024 08:22:25 EDT (-0400)
  Re: POV-Ray on non-IEEE floating-point compatible platforms  
From: Thorsten Froehlich
Date: 23 Sep 2002 08:05:38
Message: <3d8f0392$1@news.povray.org>
In article <3D8EE425.117C3945@gmx.de> , Christoph Hormann 
<chr### [at] gmxde>  wrote:

> I don't know much about these different floating point formats, but
> remember this part was exactly what caused problems when i last tried
> using POV-Ray on a SGI machine.  Will your suggestion help there or is
> that a different (64 bit specific) problem?

No, it also resolves the 64 bit specific problems.  Actually, the code below
may even work on 64 bit systems as is, because the actual bug was that the
conversion structure used 'long' rather than 'int', so it would attempt to
modify 64 bit data while it should have modified 32 bit data.

Replace the existing code with the functions shown below.  They should work
just fine now.  however, as a lack a 64 bit system to test on, I cannot tell
you for sure :-(

    Thorsten


/**************************************************************************
* Local preprocessor defines
***************************************************************************/

// WARNING: The default uses POV-Ray's own tricks which only work if
// "float" is a 32 bit IEEE 754 floating point number!  If your platform
// does not use 32 bit IEEE 754 floating point numbers, radiosity will
// be broken!!!  If you have this problem, your only other choice is to
// use an ISO C99 standard revision compatible compiler and library:
//
// Define this to 1 to use ISO C99 functions logbf, logb and copysign.
// Define this to 2 to use ISO C99 functions ilogbf, ilogb and copysign.
//
// You may want to try 1 and 2 as it cannot be generally said which one
// will be faster, but it is most likely that either 1 or 2 will perform
// slightly less well than POV-Ray's trick.  In any case, testing all
// variants (0, 1 and 2) is recommended if possible on your platform!
//
// NOTE: Of course you should put the define forC99_COMPATIBLE_RADIOSITY
// into config.h and *not* mess around with this file!!!
#ifndef C99_COMPATIBLE_RADIOSITY
#define C99_COMPATIBLE_RADIOSITY 0
#endif

int ot_point_in_node(VECTOR point, OT_ID *id)
{
  DBL sized, minx, miny, minz, lox, loy, loz, hix, hiy, hiz;

#if(C99_COMPATIBLE_RADIOSITY == 0)
  union
  {
    float f;
    int l;
  }
  size;                         /* MUST be float, NOT DBL */

  size.l = id->Size << 23;
  sized = (DBL) size.f;
#elif(C99_COMPATIBLE_RADIOSITY == 1)
  sized = pow(2.0, id->Size);
#else
  sized = (DBL)(1 << id->Size);
#endif
  minx = (DBL) id->x * sized - OT_BIAS;
  miny = (DBL) id->y * sized - OT_BIAS;
  minz = (DBL) id->z * sized - OT_BIAS;

  lox = minx - sized * .5;
  hix = minx + sized * 1.5;
  loy = miny - sized * .5;
  hiy = miny + sized * 1.5;
  loz = minz - sized * .5;
  hiz = minz + sized * 1.5;

  return(point[X] >= lox && point[X] < hix &&
         point[Y] >= loy && point[Y] < hiy &&
         point[Z] >= loz && point[Z] < hiz);
}


void ot_index_box(VECTOR min_point, VECTOR max_point, OT_ID *id)
{
  int done, idx, idy, idz;
  float dx, dy, dz, maxdel;     /* MUST BE "float" NOT "DBL" */
  DBL bsized, maxord;
#if(C99_COMPATIBLE_RADIOSITY == 0)
  union
  {
    float f;
    int l;
  }
  convert;
#endif
  OT_ID base_id, test_id;

  dx = (float) (max_point[X] - min_point[X]);
  dy = (float) (max_point[Y] - min_point[Y]);
  dz = (float) (max_point[Z] - min_point[Z]);
  maxdel = MAX3(dx, dy, dz);

  /*
   * This hex operation does a floor to next lower power of 2, by clearing
   * all of the mantissa bits.  Works only on IEEE single precision floats
   */
#if(C99_COMPATIBLE_RADIOSITY == 0)
  convert.f = maxdel;
  convert.l &= 0xff800000;
  bsized = (DBL)convert.f;
#elif(C99_COMPATIBLE_RADIOSITY == 1)
  bsized = pow(2.0, logbf(maxdel));
  bsized = copysign(bsized, maxdel);
#else
  bsized = (DBL)(1 << ilogbf(maxdel));
  bsized = copysign(bsized, maxdel);
#endif

#ifdef SAFE_METHOD

  /*
   * This block checks for the case where the node id would cause integer
   * overflow, since it is a small buffer far away
   */
  maxord = MAX3(fabs(min_point[X]), fabs(min_point[Y]), fabs(min_point[Z]));
  maxord += OT_BIAS;
  while (maxord / bsized > 1000000000.0)
  {
#ifdef RADSTATS
    overflows++;
#endif
    bsized *= 2.0;
  }
#endif

  /* calculate the smallest possible node that the item might fit into */
  base_id.x = (int) floor((min_point[X] + OT_BIAS) / bsized);
  base_id.y = (int) floor((min_point[Y] + OT_BIAS) / bsized);
  base_id.z = (int) floor((min_point[Z] + OT_BIAS) / bsized);

  /*
   * This magic hex operation extracts the exponent, which gives us an
   * integer number suitable for labelling a range of a power of 2.  In IEEE
   * format, value = pow(2,exponent-127). Therefore, if our index is, say,
   * 129, then the item has a maximum extent of (2 to the (129-127)), or
   * about 4 space units.
   */
#if(C99_COMPATIBLE_RADIOSITY == 0)
  convert.f = (float) bsized;
  base_id.Size = (convert.l & 0x7f800000) >> 23;
#elif(C99_COMPATIBLE_RADIOSITY == 1)
  base_id.Size = ((int)logb(bsized)) + 127;
#else
  base_id.Size = ilogb(bsized) + 127;
#endif

  /* Now increase the node size until it fits for sure */
#ifdef RADSTATS
  thisloops = 0;
#endif
  done = 0;
  while (!done)
  {
    test_id.Size = base_id.Size;
    for (idx = 0; idx < 2 && !done; idx++)
    {
      for (idy = 0; idy < 2 && !done; idy++)
      {
        for (idz = 0; idz < 2 && !done; idz++)
        {
          test_id.x = base_id.x + idx;
          test_id.y = base_id.y + idy;
          test_id.z = base_id.z + idz;
          if (ot_point_in_node(min_point, &test_id) &&
              ot_point_in_node(max_point, &test_id))
          {
            done = 1;
          }
        }
      }
    }

    /*
     * Debug_Info("looping %d,%d,%d,%d  min=%d, max=%d\n", test_id.x,
     * test_id.y,test_id.z, test_id.Size, ot_point_in_node(min_point,
     * &test_id), ot_point_in_node(max_point, &test_id));
     */
    ot_parent(&base_id, &base_id);
#ifdef RADSTATS
    totloops++;
    thisloops++;
#endif
  }
#ifdef RADSTATS
  if (thisloops < minloops)
    minloops = thisloops;
  if (thisloops > maxloops)
    maxloops = thisloops;
#endif
  *id = test_id;

#ifdef OT_DEBUG
  if (id->Size > 139)
  {
    Debug_Info("unusually large id, maxdel=%.4f, bsized=%.4f, isize=%d\n",
           maxdel, bsized, id->Size);
  }
#endif
}




____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.